#ifndef __drv_l1_USBH_EHCI_H__
#define __drv_l1_USBH_EHCI_H__

#include "project.h"
#include "gplib.h"
#include "drv_l1_usbh.h"

struct ehci_regs
{
	/* USBCMD: offset 0x00 */
	volatile INT32U		command;
/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
#define CMD_ASE		(1<<5)		/* async schedule enable */
#define CMD_PSE		(1<<4)		/* periodic schedule enable */
/* 3:2 is periodic frame list size */
#define CMD_RESET	(1<<1)		/* reset HC not bus */
#define CMD_RUN		(1<<0)		/* start/stop HC */

	/* USBSTS: offset 0x04 */
	volatile INT32U		status;
#define STS_ASS		(1<<15)		/* Async Schedule Status */
#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
#define STS_RECL	(1<<13)		/* Reclamation */
#define STS_HALT	(1<<12)		/* Not running (any reason) */
/* some bits reserved */
	/* these STS_* flags are also intr_enable bits (USBINTR) */
#define STS_IAA		(1<<5)		/* Interrupted on async advance */
#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
#define STS_FLR		(1<<3)		/* frame list rolled over */
#define STS_PCD		(1<<2)		/* port change detect */
#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */

	/* USBINTR: offset 0x08 */
	volatile INT32U		intr_enable;

	/* FRINDEX: offset 0x0C */
	volatile INT32U		frame_index;	/* current microframe number */
	/* CTRLDSSEGMENT: offset 0x10 */
	volatile INT32U		segment;		/* address bits 63:32 if needed */
	/* PERIODICLISTBASE: offset 0x14 */
	volatile INT32U		frame_list;		/* points to periodic list */
	/* ASYNCLISTADDR: offset 0x18 */
	volatile INT32U		async_next;		/* address of next async queue head */

	volatile INT32U		reserved [9];

	/* CONFIGFLAG: offset 0x40 */
	volatile INT32U		configured_flag;
#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */

	/* PORTSC: offset 0x44 */
	volatile INT32U		port_status [1];	/* up to N_PORTS */
/* 31:23 reserved */
#define PORT_WKOC_E		(1<<22)		/* wake on overcurrent (enable) */
#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
/* 19:16 for port testing */
#define PORT_TEST_PKT	(0x4<<16)	/* Port Test Control - packet test */
#define PORT_LED_OFF	(0<<14)
#define PORT_LED_AMBER	(1<<14)
#define PORT_LED_GREEN	(2<<14)
#define PORT_LED_MASK	(3<<14)
#define PORT_OWNER		(1<<13)		/* true: companion hc owns this port */
#define PORT_POWER		(1<<12)		/* true: has power (see PPC) */
#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))	/* USB 1.1 device */
/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
/* 9 reserved */
#define PORT_RESET		(1<<8)		/* reset port */
#define PORT_SUSPEND	(1<<7)		/* suspend port */
#define PORT_RESUME		(1<<6)		/* resume it */
#define PORT_OCC		(1<<5)		/* over current change */
#define PORT_OC			(1<<4)		/* over current active */
#define PORT_PEC		(1<<3)		/* port enable change */
#define PORT_PE			(1<<2)		/* port enable */
#define PORT_CSC		(1<<1)		/* connect status change */
#define PORT_CONNECT	(1<<0)		/* device connected */
#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
};

#define	QH_HEAD		0x00008000
#define	QH_SMASK	0x000000ff
#define	QH_CMASK	0x0000ff00
#define	QH_HUBADDR	0x007f0000
#define	QH_HUBPORT	0x3f800000
#define	QH_MULT		0xc0000000

#define	QTD_TOGGLE		(1 << 31)		/* data toggle */
#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
#define	QTD_IOC			(1 << 15)		/* interrupt on complete */
#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
#define	QTD_STS_ACTIVE	(1 << 7)		/* HC may execute this */
#define	QTD_STS_HALT	(1 << 6)		/* halted on error */
#define	QTD_STS_DBE		(1 << 5)		/* data buffer error (in HC) */
#define	QTD_STS_BABBLE	(1 << 4)		/* device was babbling (qtd halted) */
#define	QTD_STS_XACT	(1 << 3)		/* device gave illegal response */
#define	QTD_STS_MMF		(1 << 2)		/* incomplete split transaction */
#define	QTD_STS_STS		(1 << 1)		/* split transaction state */
#define	QTD_STS_PING	(1 << 0)		/* issue PING? */

struct ehci_qtd
{
	/* first part defined by EHCI spec */
	struct ehci_qtd*		hw_next;		/* see EHCI 3.5.1 */
	struct ehci_qtd*		hw_alt_next;    /* see EHCI 3.5.2 */
	INT32U			hw_token;       		/* see EHCI 3.5.3 */
	INT32U*			hw_buf[5];        		/* see EHCI 3.5.4 */
};

struct ehci_itd
{
	/* first part defined by EHCI spec */
	struct ehci_itd*		hw_next;		/* see EHCI 3.3.1 */
	INT32U			hw_transaction[8];  	/* see EHCI 3.3.2 */
    INT32U*			hw_buf[7];       		/* see EHCI 3.3.3 */
};

typedef struct ehci_itd_s
{
	/* first part defined by EHCI spec */
	INT32U			next_lp;				/* see EHCI 3.3.1 */
	INT32U			hw_transaction[8];  	/* see EHCI 3.3.2 */
    INT32U			hw_buf[7];       		/* see EHCI 3.3.3 */
} ehci_itd_t;

struct ehci_qh
{
	struct ehci_qh*	next;		 	/* see EHCI 3.6.1 */
	INT32U			info1;       	/* see EHCI 3.6.2 */
	INT32U			info2;        	/* see EHCI 3.6.2 */
	struct ehci_qtd*	qtd_current;	/* qtd list - see EHCI 3.6.4 */
	/* qtd overlay (hardware parts of a struct ehci_qtd) */
	struct ehci_qtd*	qtd_next;
	struct ehci_qtd*	alt_next;
	INT32U			hw_token;
	INT32U*			hw_buf [5];
};

/********************* Define ISO IN control bit mask (Offset + 0x180) *****************/
#define MASK_EHCI_ISOIN_CTRL_HW_EN			BIT0	/* Enable EHCI_ISOIN HW Function */
#define MASK_EHCI_ISOIN_CTRL_HEADER_UPDATE	BIT1	/* Update EHCI ISO_IN Header Value at ISOIN_HEADER */
#define MASK_EHCI_ISOIN_CTRL_LOAD_SADDR_SW	BIT3	/* Which buf to do, 0->A buf, 1->B buf */
#define MASK_EHCI_ISOIN_CTRL_BUFBOUND_EN	BIT8	/* Buffer bound function enable */

/********************* Define ISO IN frame control interrupt enable bit mask (Offset + 0x194) *****************/
#define MASK_EHCI_ISOIN_A_BUF_DONE_EN		BIT0	/* Frame A buffer done interrupt enable */
#define MASK_EHCI_ISOIN_B_BUF_DONE_EN		BIT1	/* Frame B buffer done interrupt enable */

/********************* Define ISO IN frame control interrupt bit mask (Offset + 0x198) *****************/
#define MASK_EHCI_ISOIN_A_BUF_DONE_INT		BIT0	/* Frame A buffer done interrupt */
#define MASK_EHCI_ISOIN_B_BUF_DONE_INT		BIT1	/* Frame B buffer done interrupt */
#define MASK_EHCI_ISOIN_OVERBOUND_INT		BIT4	/* Frame A/B buffer overbound interrupt */


#define BACK_SENSOR_FRAME_RATE_25    400000
#define BACK_SENSOR_FRAME_RATE       BACK_SENSOR_FRAME_RATE_25
#define BACK_SENSOR_FRAME_WIDTH  1280
#define BACK_SENSOR_FRAME_HIGH   720
//#define HOST_UVC_JPEG_CNT 5///3///10
#define HOST_UVC_ISO_Buff_CNT 4///10///3
#define HOST_UVC_iTD_Table_CNT 10
#define HOST_UVC_iTD_Table_Size 64
#define HOST_UVC_Framelist_Size 4096
#define iTD_Trans_Time 8
#define ISO_Max_Pack_Size (3*1024)    // Multi=3
#define HOST_UVC_ISO_DATA_Buff (iTD_Trans_Time*ISO_Max_Pack_Size)   // for usb2.0 each iTD table can max receive 3*8 times 
#define HOST_UVC11_ISO_DATA_Buff 0x3C0
#define HOST_FRAME_LIST_NUM		1024///256
#define HOST_ITD_MAX_BUF_SIZE	(8*3*1024)
#define HOST_EHCI_ITD_DUMMY_BUF_ADDR	0xF8500000

typedef void (*USBH_L1_EHCI_ISO_FRAME_CBK) (INT32U);

enum
{
	EHCI_HOST_NONE_EVENT,
	EHCI_HOST_ISO_FRAME_A_DONE_EVENT,
	EHCI_HOST_ISO_FRAME_A_OVERFLOW_EVENT,
	EHCI_HOST_ISO_FRAME_B_DONE_EVENT,
	EHCI_HOST_ISO_FRAME_B_OVERFLOW_EVENT,
	EHCI_HOST_ISO_TASK_TIMEOUT_EVENT,
	EHCI_HOST_ISO_TD_DONE_EVENT,
	EHCI_HOST_PORT_CONNECTED_STATUS_EVENT,
	EHCI_HOST_PORT_DISCONNECTED_STATUS_EVENT,
	EHCI_HOST_UPDATE_ITD_EVENT,
	EHCI_HOST_UPDATE_FRAME_LIST_EVENT,
	EHCI_HOST_SEND_PARKING_REVERSE_EVENT,
	EHCI_HOST_PORT_PLUG_OUT_EVENT
};

extern USBH_OPERATION_TBL	ehci_op_tbl;

extern void drv_l1_usbh_ehci_init(void);
extern void drv_l1_usbh_ehci_uninit(void);
extern INT32U drv_l1_usbh_ehci_issue_setup(ST_USBH_CTRL *Ctrl);
extern INT32U drv_l1_usbh_ehci_in_token(ST_USBH_CTRL *Ctrl);
extern INT32U drv_l1_usbh_ehci_out_token(ST_USBH_CTRL *Ctrl);
extern void drv_l1_usbh_ehci_enable_iso_get_frame(INT32U enable);
extern void drv_l1_usbh_ehci_set_iso_frame_buf(INT32U abuf, INT32U bbuf);
extern void drv_l1_usbh_ehci_iso_update_frame_buf(INT32U abuf, INT32U bbuf);
extern void drv_l1_usbh_ehci_iso_set_ep_number(INT8U num);
extern void drv_l1_usbh_ehci_iso_enable_buf_size(INT8U enable, INT32U size);
extern INT32U drv_l1_usbh_ehci_get_iso_hw_addr(INT32U buf);
extern void drv_l1_usbh_ehci_issue_reset(INT32U uiTick);
extern void drv_l1_usbh_ehci_iso_register_frame_handler(USBH_L1_EHCI_ISO_FRAME_CBK handler);
extern INT32U drv_l1_usbh_ehci_detect_port(void);
#endif